﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using InfoJetSoft.Service.XPath.Exprs;
using InfoJetSoft.Service.Util;

//CID 0766 //2011.01.23 //Begin
namespace InfoJetSoft.Service.XPath
{
    class BindingTestCalculator : ICalculator
    {
        //CID 0810 //2011.02.28 //Begin
        public bool FullPath
        {
            get { return true; }
        }
        //CID 0810 //2011.02.28 //End

        //CID 0798 //2011.02.18 //Begin
        private object baseNode = null;
        private Stack<object> contextStack = new Stack<object>();
        //CID 0798 //2011.02.18 //End
        //CID 0825 //2011.03.06 //Begin
        public List<TestedNode> TestedQNameNodes = null;
        //CID 0825 //2011.03.06 //End
        //CID 0912 //2011.05.17 //Begin
        private BindingTestData testData = null;
        private string FuncName_GetDOM = null;
        //CID 0912 //2011.05.17 //End
        //CID 0995 //2011.07.22 //Begin
        private string FuncName_getDOM = null;
        //CID 0995 //2011.07.22 //End

        //CID 0947 //2011.06.13 //Begin
        public bool IsAggregating { get; set; }
        //CID 0947 //2011.06.13 //End

        //CID 0945 //2011.06.16 //Begin
        public bool DisableFilter { get; set; }
        //CID 0945 //2011.06.16 //End

        //CID 0950 //2011.06.16 //Begin
        public bool IsExplicit { get; set; }
        //CID 0950 //2011.06.16 //End

        //CID 0912 //2011.05.17 //Begin
        public BindingTestCalculator(BindingTestData btData, XmlNamespaceManager nsResolver)
        {
            this.testData = btData;
            string docPrefix = nsResolver.LookupPrefix(JetConstant.URI_XDXDOC);
            this.FuncName_GetDOM = NamespaceUtil.toFullName(docPrefix, "GetDOM");
            //CID 0995 //2011.07.22 //Begin
            this.FuncName_getDOM = NamespaceUtil.toFullName(docPrefix, "getDOM");
            //CID 0995 //2011.07.22 //End
        }
        //CID 0912 //2011.05.17 //End

        //CID 0825 //2011.03.06 //Begin
        public void Init()
        {
            this.TestedQNameNodes = new List<TestedNode>();
            //CID 0950 //2011.06.16 //Begin
            this.IsExplicit = true;
            //CID 0950 //2011.06.16 //End
        }
        //CID 0825 //2011.03.06 //End

        //CID 0798 //2011.02.18 //Begin
        public void SetBaseNode(object node)
        {
            this.baseNode = node;
        }
        //CID 0798 //2011.02.18 //End

        //CID 0806 //2011.02.27 //Begin
        public object GetBaseNode()
        {
            return this.baseNode;
        }
        //CID 0806 //2011.02.27 //End

        //CID 0815 //2011.03.01 //Begin
        public object GetRootNode()
        {
            if (this.baseNode is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)this.baseNode;
                //CID 0957 //2011.06.21 //Begin
                if (xmlNode is XmlDocument)
                {
                    return xmlNode;
                }
                else
                {
                    return xmlNode.OwnerDocument;
                }
                //CID 0957 //2011.06.21 //End
            }
            else
            {
                throw new ExprException("BaseNode is not an XmlNode.");
            }
        }
        //CID 0815 //2011.03.01 //End

        //CID 0817 //2011.03.02 //Begin
        //CID 0889 //2011.05.24 //isEvaluating
        public object GetParentNode(object node, bool isAbbrStep)
        {
            if (node is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)node;
                if (xmlNode is XmlAttribute)
                {
                    XmlAttribute attr = (XmlAttribute)xmlNode;
                    //CID 0889 //2011.05.24 //Begin
                    if (isAbbrStep)
                    {
                        this.AddTestedQNameNode(attr.OwnerElement);
                    }
                    //CID 0889 //2011.05.24 //End
                    return attr.OwnerElement;
                }
                else
                {
                    //CID 0889 //2011.05.24 //Begin
                    if (isAbbrStep)
                    {
                        this.AddTestedQNameNode(xmlNode.ParentNode);
                    }
                    //CID 0889 //2011.05.24 //End
                    return xmlNode.ParentNode;
                }
            }
            else
            {
                throw new ExprException("Parameter is not an XmlNode.");
            }
        }
        //CID 0817 //2011.03.02 //End

        //CID 0798 //2011.02.18 //Begin
        private Stack<object> Context
        {
            get
            {
                return (Stack<object>)this.contextStack.Peek();
            }
        }
        //CID 0798 //2011.02.18 //End

        //CID 0798 //2011.02.18 //Begin
        public void NewContext()
        {
            Stack<object> context = new Stack<object>();
            INodeList nodeList = null;
            if (this.contextStack.Count > 0)
            {
                nodeList = (INodeList)this.GetContextNodes(false);
            }
            else
            {
                nodeList = this.CreateNodeList();
                nodeList.Append(this.baseNode);
            }
            context.Push(nodeList);
            this.contextStack.Push(context);
        }
        //CID 0798 //2011.02.18 //End

        //CID 0798 //2011.02.18 //Begin
        public void NewContext(object contextNode)
        {
            Stack<object> context = new Stack<object>();
            INodeList nodeList = this.CreateNodeList();
            nodeList.Append(contextNode);
            context.Push(nodeList);
            this.contextStack.Push(context);
        }
        //CID 0798 //2011.02.18 //End

        //CID 0798 //2011.02.18 //Begin
        public void DeleteContext()
        {
            this.contextStack.Pop();
        }
        //CID 0798 //2011.02.18 //End

        //CID 0797 //2011.02.27 //Begin
        //CID 0889 //2011.05.24 //isEvaluating
        public INodeList GetContextNodes(bool isAbbrStep)
        {
            object nodes = this.Context.Peek();
            //CID 0889 //2011.05.24 //Begin
            if (isAbbrStep)
            {
                INodeList nodeList = (INodeList)nodes;
                foreach (object node in nodeList)
                {
                    this.AddTestedQNameNode(node);
                }
            }
            //CID 0889 //2011.05.24 //End
            return (INodeList)nodes;  
        }
        //CID 0797 //2011.02.27 //End

        //CID 0798 //2011.02.18 //Begin
        public void Slash(object contextNodes)
        {
            if (contextNodes is INodeList)
            {
                this.Context.Push(contextNodes);
            }
            else
            {
                throw new Exception("Not context nodes: " + contextNodes);
            }
        }
        //CID 0798 //2011.02.18 //End

        //CID 0798 //2011.02.18 //Begin
        public void SlashSlash(object nodes)
        {
            if (nodes is INodeList)
            {
                INodeList nodeList = (INodeList)nodes;
                BindingTestNodeList resultNodeList = new BindingTestNodeList();
                foreach (XmlNode node in nodeList)
                {
                    //CID 0818 //2011.03.02 //Begin
                    XmlNodeList xNodeList = node.SelectNodes("descendant-or-self::node()");
                    //CID 0818 //2011.03.02 //End
                    foreach (XmlNode xmlNode in xNodeList)
                    {
                        resultNodeList.Add(xmlNode);
                    }
                }
                this.Slash(resultNodeList);
            }
        }
        //CID 0798 //2011.02.18 //End

        //CID 0816 //2011.03.02 //Begin
        public void Axis(string axisName)
        {
            object nodes = this.Context.Peek();
            if (nodes is BindingTestNodeList)
            {
                //CID 0947 //2011.06.12 //Begin
                if (axisName.Equals("preceding-sibling") || axisName.Equals("following-sibling"))
                {
                    //Use current context still.
                }
                else
                {
                    BindingTestNodeList nodeList = (BindingTestNodeList)nodes;
                    BindingTestNodeList resultNodeList = new BindingTestNodeList();
                    foreach (XmlNode node in nodeList)
                    {
                        //CID 0818 //2011.03.02 //Begin
                        XmlNodeList xNodeList = node.SelectNodes(axisName + "::node()");
                        //CID 0818 //2011.03.02 //End
                        foreach (XmlNode xmlNode in xNodeList)
                        {
                            resultNodeList.Add(xmlNode);
                        }
                    }
                    this.Context.Push(resultNodeList);
                }
                //CID 0947 //2011.06.12 //End
                if (axisName.Equals("attribute") || axisName.Equals("namespace"))
                {
                    this.axisOnAttributes = true;
                }
                else
                {
                    this.axisOnAttributes = false;
                }
            }
            else
            {
                throw new Exception("Unsupported data type: " + nodes);
            }
        }
        //CID 0819 //2011.03.02 //End

        //CID 0819 //2011.03.02 //Begin
        private bool axisOnAttributes = false;
        //CID 0819 //2011.03.02 //End

        //CID 0909 //2011.05.15 //Begin
        public bool IsLastStep { get; set; }
        //CID 0909 //2011.05.15 //End

        //CID 0798 //2011.02.18 //Begin
        public object NameTest(string name)
        {
            string prefix = "";
            string localName = "";
            int index = name.IndexOf(":");
            if (index > 0)
            {
                prefix = name.Substring(0, index);
                localName = name.Substring(index + 1);
            }
            else
            {
                prefix = "";
                localName = name;
            }
            //CID 0905 //2011.05.24 //Begin
            bool isName = true;
            if (name.Equals("*") || localName.Equals("*"))
            {
                isName = false;
            }
            //CID 0905 //2011.05.24 //End
            object contextNodes = this.Context.Peek();
            if (contextNodes is BindingTestNodeList)
            {
                BindingTestNodeList nodeList = (BindingTestNodeList)contextNodes;
                BindingTestNodeList resultNodeList = new BindingTestNodeList();
                foreach (XmlNode node in nodeList)
                {
                    if (name.Equals("*"))
                    {
                        //CID 0818 //2011.03.02 //Begin
                        this.AddAxisNode(resultNodeList, node);
                        //CID 0818 //2011.03.02 //End
                    }
                    else if (localName.Equals("*"))
                    {
                        if (node.Prefix.Equals(prefix))
                        {
                            //CID 0818 //2011.03.02 //Begin
                            this.AddAxisNode(resultNodeList, node);
                            //CID 0818 //2011.03.02 //End
                        }
                    }
                    else
                    {
                        if (node.Prefix.Equals(prefix) && node.LocalName.Equals(localName))
                        {
                            //CID 0818 //2011.03.02 //Begin
                            object testedQNameNode = this.AddAxisNode(resultNodeList, node);
                            //CID 0889 //2011.05.24 //Begin
                            this.AddTestedQNameNode(testedQNameNode);
                            //CID 0889 //2011.05.24 //End
                            //CID 0818 //2011.03.02 //End
                        }
                    }
                }
                //CID 0905 //2011.05.24 //Begin
                if (isName && resultNodeList.Count <= 0)
                {
                    //CID 0950 //2011.06.16 //Begin
                    this.IsExplicit = false;
                    //CID 0950 //2011.06.16 //End
                }
                //CID 0905 //2011.05.24 //End
                return resultNodeList;
            }
            throw new Exception("Unsupported NameTest: " + contextNodes);
        }
        //CID 0818 //2011.03.02 //End

        //CID 0889 //2011.05.24 //Begin
        private void AddTestedQNameNode(object testedQNameNode)
        {
            if (testedQNameNode == null)
            {
                return;
            }
            //CID 0825 //2011.03.06 //Begin
            //CID 0909 //2011.05.15 //Begin
            if (this.IsLastStep)
            {
                XmlNode xmlTestedQNameNode = (XmlNode)testedQNameNode;
                //CID 0947 //2011.06.13 //Begin
                bool found = false;
                foreach (TestedNode tqNode in this.TestedQNameNodes)
                {
                    if (tqNode.Node.Equals(xmlTestedQNameNode))
                    {
                        if (this.IsAggregating)
                        {
                            tqNode.InAggregation = this.IsAggregating;
                        }
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    TestedNode testedNode = new TestedNode();
                    testedNode.Node = xmlTestedQNameNode;
                    testedNode.InAggregation = this.IsAggregating;
                    this.TestedQNameNodes.Add(testedNode);
                }
                //CID 0947 //2011.06.13 //End
            }
            //CID 0909 //2011.05.15 //End
            //CID 0825 //2011.03.06 //End
        }
        //CID 0889 //2011.05.24 //End

        //CID 0818 //2011.03.02 //Begin
        private object AddAxisNode(BindingTestNodeList resultNodeList, XmlNode node)
        {
            if (this.axisOnAttributes && node is XmlAttribute)
            {
                if (!resultNodeList.Contains(node))
                {
                    resultNodeList.Add(node);
                    return node;
                }
            }
            else if (node is XmlElement)
            {
                if (!resultNodeList.Contains(node))
                {
                    resultNodeList.Add(node);
                    return node;
                }
            }
            return null;
        }
        //CID 0818 //2011.03.02 //End

        //CID 0821 //2011.03.03 //Begin
        public object NodeType(string type)
        {
            int nodeType = 0;
            if (type.Equals("node"))
            {
                nodeType = 1;
            }
            else if (type.Equals("text"))
            {
                nodeType = 2;
            }
            else if (type.Equals("comment"))
            {
                nodeType = 3; 
            }
            else
            {
                throw new ExprException("Unsupported NodeType: " + type);
            }
            object contextNodes = this.Context.Peek();
            if (contextNodes is BindingTestNodeList)
            {
                BindingTestNodeList nodeList = (BindingTestNodeList)contextNodes;
                BindingTestNodeList resultNodeList = new BindingTestNodeList();
                foreach (XmlNode node in nodeList)
                {
                    if (nodeType == 1)
                    {
                        resultNodeList.Add(node);
                    }
                    else if (nodeType == 2 && node is XmlText)
                    {
                        resultNodeList.Add(node);
                    }
                    else if (nodeType == 3 && node is XmlComment)
                    {
                        resultNodeList.Add(node);
                    }
                }
                return resultNodeList;
            }
            throw new Exception("Unsupported NodeType: " + contextNodes);
        }
        //CID 0821 //2011.03.03 //End

        //CID 0822 //2011.03.03 //Begin
        public object PI(string name)
        {
            object contextNodes = this.Context.Peek();
            if (contextNodes is BindingTestNodeList)
            {
                BindingTestNodeList nodeList = (BindingTestNodeList)contextNodes;
                BindingTestNodeList resultNodeList = new BindingTestNodeList();
                foreach (XmlNode node in nodeList)
                {
                    if (node is XmlProcessingInstruction)
                    {
                        XmlProcessingInstruction pi = (XmlProcessingInstruction)node;
                        if (name == null)
                        {
                            resultNodeList.Add(pi);
                        }
                        else if (pi.Name.Equals(name))
                        {
                            resultNodeList.Add(pi);
                        }
                    }
                }
                return resultNodeList;
            }
            throw new Exception("Unsupported PI: " + contextNodes);
        }
        //CID 0822 //2011.03.03 //End

        //CID 0824 //2011.03.03 //Begin
        public object ResolveVariable(string name)
        {
            INodeList emptyNodeList = this.CreateNodeList();
            return emptyNodeList;
        }
        //CID 0824 //2011.03.03 //End

        //CID 0826 //2011.03.06 //Begin
        public object CallCustomFunction(string name, List<object> args)
        {
            //CID 0947 //2011.06.13 //Begin
            if (name.Equals("count") || name.Equals("sum"))
            {
                this.IsAggregating = true;
            }
            //CID 0947 //2011.06.13 //End
            //CID 0995 //2011.07.22 //Begin
            if (name.Equals(this.FuncName_getDOM))
            {
                INodeList nodeList = this.CreateNodeList();
                nodeList.Append(this.testData.Main);
                return nodeList;
            }
            //CID 0995 //2011.07.22 //End
            if (name.Equals(this.FuncName_GetDOM))
            {
                //CID 0952 //2011.06.17 //Begin
                XmlDocument dataDoc = null;
                string sdsName = args[0] as string;
                if( this.testData.Sources.ContainsKey(sdsName) )
                {
                    dataDoc = this.testData.Sources[sdsName];
                }
                else
                {
                    dataDoc = new XmlDocument();
                }
                //CID 0952 //2011.06.17 //End
                INodeList nodeList = this.CreateNodeList();
                nodeList.Append(dataDoc);
                return nodeList;
            }
            INodeList emptyNodeList = this.CreateNodeList();
            return emptyNodeList;
        }
        //CID 0826 //2011.03.06 //End

        public INodeList CreateNodeList()
        {
            BindingTestNodeList nodeList = new BindingTestNodeList();
            return nodeList;
        }

        public string GetNodeValue(object node)
        {
            if (node is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)node;
                if (node is XmlElement)
                {
                    return xmlNode.InnerText;
                }
                else if (node is XmlAttribute)
                {
                    return xmlNode.Value;
                }
                else
                {
                    return xmlNode.OuterXml;
                }
            }
            else
            {
                throw new Exception("Node is not XmlNode.");
            }
        }

        //CID 0797 //2011.02.28 //Begin
        public string GetNodeLocalName(object node)
        {
            if (node is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)node;
                return xmlNode.LocalName;
            }
            else
            {
                throw new Exception("Node is not XmlNode.");
            }
        }
        //CID 0797 //2011.02.28 //End

        //CID 0797 //2011.02.28 //Begin
        public string GetNodeNamespaceUri(object node)
        {
            if (node is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)node;
                return xmlNode.NamespaceURI;
            }
            else
            {
                throw new Exception("Node is not XmlNode.");
            }
        }
        //CID 0797 //2011.02.28 //End

        //CID 0797 //2011.02.28 //Begin
        public string GetNodeName(object node)
        {
            if (node is XmlNode)
            {
                XmlNode xmlNode = (XmlNode)node;
                return xmlNode.Name;
            }
            else
            {
                throw new Exception("Node is not XmlNode.");
            }
        }
        //CID 0797 //2011.02.28 //End
    }
}
//CID 0766 //2011.01.23 //End